package com.game.base;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.Timer;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.phprpc.util.PHPSerializer;
import org.xsocket.connection.INonBlockingConnection;

import sun.rmi.runtime.Log;

import com.game.database.MysqlHelper;
import com.game.manager.CommManager;
import com.game.manager.ErrorManager;
import com.game.manager.LookUpManager;
import com.game.manager.ScheduleManager;
import com.game.manager.SobManager;
import com.game.performers.Actor;
import com.game.task.CommSendChanges;
import com.game.task.EnvStateUpdate;
import com.game.task.MainTick;
import com.game.task.SobCacheClear;
import com.module.login.LoginManager;
import com.server.User;

public class BaseSimulation extends SimulationObject {
	private static final long serialVersionUID = 524680085369867951L;
	
	protected static BaseSimulation instance;
	
	public static BaseSimulation get(){
		return instance;
	}
	
	private SimulationObject root;
	
	public HashMap<String, User> onlineusers = new HashMap<String, User>();
	public HashMap<Integer, INonBlockingConnection> userconns = new HashMap<Integer, INonBlockingConnection>();
	
	public BaseSimulation(){
		instance = this;
		initRoot();
		initObjects();
		initTask();
	}
	
	protected void initRoot(){
		this.root = SobManager.get().getSob(SimulationObject.ROOT);
		if(this.root == null){
			Logger.getRootLogger().info(new Date() +"混沌刚出，世界伊始，万物始一！");
			SimulationObject sob = SobFactory.create(SimulationObject.class.getName());
			sob.pid = 0;
			try {
				sob.id = SimulationObject.ROOT;
				byte[] rs = new PHPSerializer().serialize(sob);
				Object[] obj = new Object[2];
				obj[0] = SimulationObject.ROOT;
				obj[1] = rs;
				sob.id = MysqlHelper.ExecuteInsert("insert into obj_item (`id`,`data`) values (?,?)", obj);
				updateSysTime();
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.root = SobManager.get().getSob(SimulationObject.ROOT);
		}
	}
	
	protected void initTask(){
		ScheduleManager.get().scheduleWithFixedDelay(new CommSendChanges(), 0, 1000, TimeUnit.MICROSECONDS);
		ScheduleManager.get().scheduleWithFixedDelay(new MainTick(), 1000, 100, TimeUnit.MICROSECONDS);
		ScheduleManager.get().scheduleWithFixedDelay(new SobCacheClear(), 0, 12, TimeUnit.HOURS);
		ScheduleManager.get().scheduleWithFixedDelay(new EnvStateUpdate(), 0, 1, TimeUnit.MINUTES);
	}
	
	protected void initObjects(){
		
	}
	
	public void attachUser(User user, INonBlockingConnection nbc){
		System.out.println(user.account+" 上线……");
		if(onlineusers.containsValue(user)){
			INonBlockingConnection oldconn = null;
			if(user.ctrl == 1){
				oldconn = userconns.get(user.id);
			} else if(user.ctrl > 1){
				oldconn = CommManager.get().conns.get(user.ctrl);
			}
			if(oldconn != null){
				ErrorManager.sendError(oldconn, ErrorManager.SencondConnKickOut);
				this.detachUser(user, oldconn);
				try {
					oldconn.close();	
				} catch (Exception e) {
					ErrorManager.sendError(oldconn, ErrorManager.FouseToOfflineFailed);
				}
			}
		}
		onlineusers.put(nbc.getId(), user);
		userconns.put(user.id, nbc);
	}
	
	public void detachUser(User user, INonBlockingConnection nbc){
		if(user!=null){
			CommManager.get().unSubscribe(nbc);
			LoginManager.logout(user);
			onlineusers.remove(nbc.getId());
			System.out.println(user.account+" 下线……");
		}
	}
	
	public void shutDown(){
		
	}
	
	public void startUp(){
		
	}
	
	public void updateEnv(){
		Object[] parms = new Object[1];
		try {
			parms[0] = new Date().getTime()-Long.valueOf((String) MysqlHelper.ExecuteScalar("select `value` from env_state where `name`='lastupdatetime'", null));
			MysqlHelper.ExecuteNoneQuery("update env_state set `value` = value+? where `name`='simulationtime'", parms);
			parms[0] = new Date().getTime();
			MysqlHelper.ExecuteNoneQuery("update env_state set `value` = ? where `name` = 'lastupdatetime'", parms);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void tick(){
		
	}
	
	private void updateSysTime(){
		Object[] parms = new Object[1];
		parms[0] = new Date().getTime();
		try {
			MysqlHelper.ExecuteNoneQuery("update env_state set `value` = ? where `name` = 'lastupdatetime'", parms);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
